package sg.edu.nus.comp.cs4218.impl;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;

import sg.edu.nus.comp.cs4218.extended2.IPasteTool;

public class PasteTool extends ATool implements IPasteTool {

	public PasteTool(String[] args) {
		super(args);
	}

	/**
	 * Paste one file at a time instead of in parallel
	 * 
	 * @param input
	 *            - An array containing of file directories with file names
	 * @return A string representation of the pasted content of the files
	 */
	@Override
	public String pasteSerial(String[] input) {
		String content = input[0];
		String[] strArray = content.split("\n");
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < strArray.length; i++) {
			sb.append(strArray[i] + "\n");
		}
		setStatusCode(0);
		return sb.toString().trim();
	}

	/**
	 * Use characters from the DELIM instead of TAB character
	 * 
	 * @param delim
	 *            - The delimiters to be used to paste the files input - An
	 *            array containing of texts to be pasted
	 * 
	 * @return A string representation of the pasted content of the files
	 */

	@Override
	public String pasteUseDelimiter(String delim, String[] input) {
		String[] delimArray = getCharArray(delim, input.length);
		String line = "";
		int maxNoOfLines = 0;
		StringBuilder sb = new StringBuilder();
		ArrayList<String[]> contentList = new ArrayList<String[]>();

		for (int i = 0; i < input.length; i++) {
			String[] strArray = input[i].split("\n");
			contentList.add(strArray);
			if (strArray.length > maxNoOfLines) {
				maxNoOfLines = strArray.length;
			}
		}

		line = contentList.get(0)[0];
		for (int p = 1; p < contentList.size(); p++) {

			// line += delim + contentList.get(p)[0];
			line += delimArray[p - 1] + contentList.get(p)[0];
		}
		sb.append(line);
		for (int j = 1; j < maxNoOfLines; j++) {
			if (j > (contentList.get(0).length - 1)) {
				line = "\t";
			} else {
				line = contentList.get(0)[j];
			}
			for (int k = 1; k < contentList.size(); k++) {
				if (j > (contentList.get(k).length - 1)) {
					// line += delim + "\t";
					line += delimArray[k - 1] + "\t";
				} else {
					// line += delim + contentList.get(k)[j];
					line += delimArray[k - 1] + contentList.get(k)[j];
				}
			}
			sb.append("\n" + line);

		}
		return sb.toString();
	}

	/**
	 * Brief information about supported options
	 * 
	 * @return A string representation of the help message
	 */
	@Override
	public String getHelp() {
		setStatusCode(0);
		return "-s : paste one file at a time instead of in parallel\t"
				+ " -d DELIM: Use characters from the DELIM instead of TAB character\t"
				+ " -help : Brief information about supported options";
	}

	/**
	 * An execute method used by other classes
	 * 
	 * @param workingDir
	 *            - A file directory with file name stdin - The standard input
	 *            from users
	 * @return A string representation of the status message returned from the
	 *         related method
	 */

	@Override
	public String execute(File workingDir, String stdin) {
		String result = null;
		if (args != null && args.length != 0) {
			if (args.length == 1) {
				result = oneArg(workingDir, stdin);
			} else {
				result = moreThanOneArg(workingDir, stdin);
			}
		} else {
			setStatusCode(1);
			result = "No argument.";
		}
		return result;
	}

	/**
	 * A method to be executed when there is only 1 argument
	 * 
	 * @param workingDir
	 *            - The working directory where the files are storing stdin -
	 *            The standard input from users
	 * @return A string representation of the resulting outcome or error message
	 *         returned from the related method
	 */
	private String oneArg(File workingDir, String stdin) {
		String result;
		if (args[0].equals("-help")) {
			result = getHelp();
		} else if (args[0].equals("-") || isExisting(workingDir, args[0])) {
			result = pasteUseDelimiter(workingDir, stdin, 0);
		} else {
			setStatusCode(1);
			result = "Wrong command.";
		}
		return result;
	}

	/**
	 * A method to be executed when there is more than 1 argument
	 * 
	 * @param workingDir
	 *            - The working directory where the files are storing stdin -
	 *            The standard input from users
	 * @return A string representation of the resulting outcome or error message
	 *         returned from the related method
	 */
	private String moreThanOneArg(File workingDir, String stdin) {
		String result = null;
		if (args[0].equals("-s")) {
			result = pasteSerial(workingDir, stdin);
		} else if (args[0].equals("-d")) {
			if (args.length == 2) {
				result = "Wrong command.";
			} else {
				result = pasteUseDelimiter(workingDir, stdin, 2);
			}
		} else if (isExisting(workingDir, args[0]) || args[0].equals("-")) {
			result = pasteUseDelimiter(workingDir, stdin, 0);
		} else {
			setStatusCode(1);
			result = "Wrong command.";
		}
		return result;
	}

	/**
	 * A method to link other methods and the specific pasteUseDeliter(String
	 * delim, String[] input) method
	 * 
	 * @param workingDir
	 *            - The working directory where the files are storing stdin -
	 *            The standard input from users start - the starting index of
	 *            the argments array to be pasted, start must be non-negative
	 * @return A string representation of the resulting outcome or error message
	 *         returned from the related method
	 */
	private String pasteUseDelimiter(File workingDir, String stdin, int start) {
		String result = "";
		String errMsg = "";
		String op = "\t";
		Boolean filesExisting = true;
		String[] contentArray = new String[args.length - start];
		for (int i = start; i < args.length; i++) {
			if (isExisting(workingDir, args[i])) {
				contentArray[i - start] = readContentFromFile(workingDir,
						args[i]);
			} else if (args[i].equals("-")) {
				if (stdin == null || stdin == "") {
					filesExisting = false;
					errMsg = "Standard input is empty or null.";
				} else {
					contentArray[i - start] = stdin;
				}
			} else {
				setStatusCode(1);
				filesExisting = false;
				errMsg = workingDir.toString() + "\\" + args[i]
						+ " was not found.";
			}
		}
		if (filesExisting) {
			
			if (start == 0) {
				 op = "\t";
				
			} else {
				
				 op = args[1];
			}
			
						
			result = pasteUseDelimiter(op, contentArray);
		} else {
			result = errMsg;
		}
		return result;
	}

	/**
	 * A method to link other methods and the specific pasteSerial(String[]
	 * input) method
	 * 
	 * @param workingDir
	 *            - The working directory where the files are storing stdin -
	 *            The standard input from users
	 * @return A string representation of the resulting outcome or error message
	 *         returned from the related method
	 */
	private String pasteSerial(File workingDir, String stdin) {
		StringBuilder sb = new StringBuilder();
		String content = null;
		String[] contentArray = new String[1];
		Boolean success = true;

		for (int i = 1; i < args.length; i++) {
			if (isExisting(workingDir, args[i])) {
				content = readContentFromFile(workingDir, args[i]);
			} else if (args[i].equals("-")) {
				content = stdin;
			} else {
				setStatusCode(1);
				success = false;
				content = workingDir.toString() + "\\" + args[i]
						+ " was not found.";
			}
			if (!success) {
				sb = new StringBuilder();
				sb.append(content);
				break;
			} else {
				contentArray[0] = content;
				sb.append(pasteSerial(contentArray) + "\n");
			}
		}

		return sb.toString().trim();
	}

	private String[] getCharArray(String delim, int contentArrayLength) {
		String[] charArray = new String[contentArrayLength - 1];
		if (delim.equals("\t")) {
			for (int i = 0; i < charArray.length; i++) {
				charArray[i] = "\t";				
			}
		} else {
			for (int i = 0; i < charArray.length; i++) {
				charArray[i] = "" + delim.charAt(i);
			}
		}
		return charArray;
	}

	/**
	 * A method to check if a file is existing in the working directory
	 * 
	 * @param workingDir
	 *            - The working directory where the files are storing fileName -
	 *            A string representation of the file name
	 * @return A boolean representation if the file is existing
	 */
	private boolean isExisting(File workingDir, String fileName) {
		File f = new File(workingDir, fileName);
		if (f.exists()) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * A method to be called when reading the contents of a specified file
	 * 
	 * @param workingDir
	 *            - The working directory where the files are storing fileName -
	 *            A string representation of the file name
	 * @return A string representation of the contents of the file or error
	 *         message
	 */
	private static String readContentFromFile(File workingDir, String fileName) {
		String content = "";
		Scanner in = null;
		try {
			File f = new File(workingDir, fileName);
			in = new Scanner(f);
			while (in.hasNextLine()) {
				content = content + in.nextLine() + "\n";
			}
		} catch (FileNotFoundException e) {
			content = fileName + " not found.";
		} finally {
			in.close();
		}
		return content.trim();
	}

}
